package com.org.devg.devgfilesync.config.batch;

import com.alibaba.fastjson.JSONObject;
import com.org.devg.devgfilesync.utils.CommonUtil;
import com.org.devg.devgfilesync.utils.HttpUtil;
import com.org.devg.devgfilesync.web.file.service.FileService;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

@Configuration
@EnableScheduling
public class FileSyncTask {

  public static final String fileSync = "FILE_SYNC";

  private static final Logger log = LoggerFactory.getLogger(FileSyncTask.class);

  @Autowired
  private FileService fileService;

  @Value("${file.syncUrl}")
  private String syncUrl;

  @Value("${file.rootPath}")
  private String rootPath;

  @Value("${file.threadNum}")
  private Integer threadNum;

  @Value("${file.preSyncNum}")
  private Integer preSyncNum;

  @Scheduled(cron = "0/2 * * * * ? ")
  public void fileSync() {
    log.info("文件同步开始");
    int i = fileService.updateSyncRun(fileSync);
    if (i != 1) {
      log.info("文件同步正在处理中...");
      return;
    }
    try {
      Map<String, Object> syncConfigMap = new HashMap<>();
      syncConfigMap.put("syncConfigName", fileSync);
      Map<String, Object> syncConfigResult = fileService.getSyncConfig(syncConfigMap);
      String theRootPath = CommonUtil.getMapString(syncConfigResult, "rootPath", rootPath);
      String theSyncUrl = CommonUtil.getMapString(syncConfigResult, "syncUrl", syncUrl);
      Integer theThreadNum = CommonUtil.getMapInteger(syncConfigResult, "threadNum", threadNum);
      Integer thePreSyncNum = CommonUtil.getMapInteger(syncConfigResult, "preSyncNum", preSyncNum);
      List<Map<String, Object>> fileList = fileService.selectFileList(thePreSyncNum);
      if (null != fileList && fileList.size() > 0) {
        List<Future<Map<String, Object>>> futurelist = new ArrayList<>(fileList.size());
        ExecutorService executorService = Executors.newFixedThreadPool(theThreadNum);
        for (Map<String, Object> fileMap : fileList) {
          Callable<Map<String, Object>> fileSyncCallable = new FileSync(fileMap, theRootPath, theSyncUrl);
          FutureTask<Map<String, Object>> futureTask = new FutureTask<>(fileSyncCallable);
          executorService.execute(futureTask);
          futurelist.add(futureTask);
        }
        List<String> successFileIdList = new ArrayList<>();
        List<String> errorFileIdList = new ArrayList<>();
        for (Future<Map<String, Object>> future : futurelist) {
          Map<String, Object> futureMap = future.get();
          Integer code = CommonUtil.getMapInteger(futureMap, "code");
          String fileId = CommonUtil.getMapString(futureMap, "fileId");
          if (null != code && code.equals(1) && !CommonUtil.isEmpty(fileId)) {
            successFileIdList.add(fileId);
          }
          if (null != code && code.equals(0) && !CommonUtil.isEmpty(fileId)) {
            errorFileIdList.add(fileId);
          }
        }
        executorService.shutdown();
        if (successFileIdList.size() > 0) {
          Map<String, Object> fileMap = new HashMap<>();
          fileMap.put("list", successFileIdList);
          fileMap.put("syncStatus", 1);
          fileService.updateSyncStatus(fileMap);
        }
        if (errorFileIdList.size() > 0) {
          Map<String, Object> fileMap = new HashMap<>();
          fileMap.put("list", errorFileIdList);
          fileMap.put("syncStatus", 2);
          fileService.updateSyncStatus(fileMap);
        }
      }
    } catch (Exception ex) {
      log.error("文件同步出错:", ex);
    } finally {
      fileService.updateSyncStop(fileSync);
      log.info("文件同步结束");
    }
  }


  public static final class FileSync implements Callable<Map<String, Object>> {

    private Map<String, Object> fileMap;

    private String theRootPath;

    private String theSyncUrl;

    public FileSync(Map<String, Object> fileMap, String theRootPath, String theSyncUrl) {
      this.fileMap = fileMap;
      this.theRootPath = theRootPath;
      this.theSyncUrl = theSyncUrl;
    }

    @Override
    public Map<String, Object> call() {
      Map<String, Object> result = new HashMap<>();
      // 默认同步失败
      Integer code = 0;
      String fileId = null;
      try {
        fileId = CommonUtil.getMapString(fileMap, "fileId");
        String filePath = CommonUtil.getMapString(fileMap, "filePath");
        String fileAbsolutePath = CommonUtil.changePath(theRootPath) + filePath;
        File file = new File(fileAbsolutePath);
        JSONObject jsonObject = HttpUtil.httpRequest(theSyncUrl, file, fileId, filePath);
        if (null != jsonObject) {
          String httpCode = jsonObject.getString("code");
          if (null != httpCode && httpCode.equals("200")) {
            code = 1;
          }
        }
      } catch (Exception ex) {
        log.error("调用文件同步接口出错:", ex);
      }
      result.put("code", code);
      result.put("fileId", fileId);
      return result;
    }
  }

}
